/*
 * @Author: your name
 * @Date: 2021-04-09 13:46:48
 * @LastEditTime: 2021-05-07 10:22:49
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /vite-project/src/utils/http/Axios.ts
 */

import axios from "axios";
import type {AxiosInstance, AxiosRequestConfig, AxiosResponse} from "axios";
import {RequestOptions, CreateAxiosOptions, Result} from "./types"
import { isFunction } from "../is";
import { cloneDeep} from "@/utils/lodashChunk"

export class HAxios {
    private axiosInstance: AxiosInstance;
    private options: CreateAxiosOptions;

    constructor(options: CreateAxiosOptions) {
        this.options = options;
        this.axiosInstance = axios.create(options);
        this.setupInterceptors();
    }

    /**
     * @description: 创建axios实例
     * @param {CreateAxiosOptions} config
     * @return {*}
     */
    private createAxios(config: CreateAxiosOptions): void {
        this.axiosInstance = axios.create(config);
    }

    private getTransform() {
        const {transform}  = this.options;
        return transform
    }

    getAxios(): AxiosInstance {
        return this.axiosInstance;
    }

    /**
     * @description: 重新配置axios
     * @param {CreateAxiosOptions} config
     * @return {*}
     */
    configAxios(config: CreateAxiosOptions) {
        if (!this.axiosInstance) {
            return;
        }
        this.createAxios(config);
    }

    /**
     * @description: 设置通用的header
     * @param {any} headers
     * @return {*}
     */
    setHeader(headers: any): void {
        if (!this.axiosInstance) {
            return;
        }
        Object.assign(this.axiosInstance.defaults.headers, headers);
    }

    /**
     * @description: 拦截器配置
     * @param {*}
     * @return {*}
     */
    private setupInterceptors() {
        const transform = this.getTransform();
        if (!transform) {
            return;
        }
        const {requestInterceptors, requestInterceptorsCatch, responseInterceptors, responseInterceptorsCatch} = transform;

        // 请求拦截器配置处理
        this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
            if (requestInterceptors && isFunction(requestInterceptors)) {
                config = requestInterceptors(config);
            }
            return config;
        }, undefined);

        // 请求拦截器错误捕获
        requestInterceptorsCatch && isFunction(requestInterceptorsCatch) && this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);

        // 响应结果拦截器处理
        this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
            if (responseInterceptors && isFunction(responseInterceptors)) {
                res = responseInterceptors(res);
            }
            return res;
        }, undefined);

        // 响应结果拦截器错误捕获
        responseInterceptorsCatch && isFunction(responseInterceptorsCatch) && this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
    }

      // /**
  //  * @description:  文件上传
  //  */
  // uploadFiles(config: AxiosRequestConfig, params: File[]) {
  //   const formData = new FormData();

  //   Object.keys(params).forEach((key) => {
  //     formData.append(key, params[key as any]);
  //   });

  //   return this.request({
  //     ...config,
  //     method: 'POST',
  //     data: formData,
  //     headers: {
  //       'Content-type': ContentTypeEnum.FORM_DATA,
  //     },
  //   });
  // }

  /**
   * @description: 请求方法
   * @param {AxiosRequestConfig} config
   * @param {RequestOptions} options
   * @return {*}
   */
  request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
      // 深拷贝
    let conf: AxiosRequestConfig = cloneDeep(config);
    const transform = this.getTransform();

    // 创建axios对象传入的options(例如：请求时间等)
    const { requestOptions } = this.options;

    // 将requestOptions和options合并到一个对象里面
    const opt: RequestOptions = Object.assign({}, requestOptions, options);

    const {beforeRequestHook, requestCatch, transformRequestData} = transform || {};
    if (beforeRequestHook && isFunction(beforeRequestHook)) {
        conf = beforeRequestHook(conf, opt);
    }
    return new Promise((resolve, reject) => {
        this.axiosInstance.request<any, AxiosResponse<Result>>(conf).then((res: AxiosResponse<Result>) => {
            if (transformRequestData && isFunction(transformRequestData)) {
                const ret = transformRequestData(res, opt);
                return resolve(ret);
            }
            reject((res as unknown) as Promise<T>);
        }).catch((e: Error) => {
            if (requestCatch && isFunction(requestCatch)) {
                reject(requestCatch(e));
                return;
            }
            reject(e);
        })
    })
  }
}